package com.example.demo.game;

import com.example.demo.DemoApplication;
import com.example.demo.model.User;
import com.example.demo.model.UserMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.UUID;

/**
 * @Author: 啵啵虎
 * @Date: 2024-05-07  13:31
 */

//这个类表示一个游戏房间
public class Room {
    private String roomId;
    private User user1;
    private User user2;
    private int whiteUser;

    private static final int MAX_ROW=15;
    private static final int MAX_COL=15;

    //表示棋盘
    //0表示未落子
    //1表示玩家1的落子位置
    //2表示玩家2的落子位置
    private int[][] board=new int[MAX_ROW][MAX_COL];

    //创建objectMapper用来转换JSON
    private ObjectMapper objectMapper=new ObjectMapper();

    //引入OnlineUserManager
//    @Autowired
    private OnlineUserManager onlineUserManager;

//    @Autowired
    private RoomManager roomManager;

//    @Autowired
    private UserMapper userMapper;

    //通过方法来处理一次落子请求
    //1、记录当前落子的请求
    //2、进行胜负判定
    //3、给客户端返回响应
    public void putChess(String jsonString) throws IOException {
        //1、记录当前落子的位置
        GameRequest request=objectMapper.readValue(jsonString,GameRequest.class);
        GameResponse response=new GameResponse();
        //当前这个子是玩家1落的还是玩家2落的
        int chess= request.getUserId()==user1.getUserId()?1:2;
        int row= request.getRow();
        int col= request.getCol();
        if (board[row][col]!=0){
            //在客户端已经针对重复落子进行过判定了，再次判定
            System.out.println("当前位置("+row+","+col+")已经有子了！");
            return;
        }
        board[row][col]=chess;
        //2、打印出当前的棋盘信息，方便来观察局势，也方便后面验证胜负关系的判定
        printBoard();
        //3、进行胜负判定
        int winner=checkWinner(row,col,chess);
        //4、给房间中的所有客户端返回响应
        response.setMessage("putChess");
        response.setUserId(request.getUserId());
        response.setRow(row);
        response.setCol(col);
        response.setWinner(winner);
        //要想给用户发送websocket数据，就要获得这个用户的websocketSession
        WebSocketSession session1= onlineUserManager.getFromGameRoom(user1.getUserId());
        WebSocketSession session2= onlineUserManager.getFromGameRoom(user2.getUserId());
        //万一当前查到的会话为空（玩家已经下线）特殊处理一下
        if (session1==null){
            //玩家1已经下线了，直接认为玩家2获胜
            response.setWinner(user2.getUserId());
            System.out.println("玩家1 掉线！");
        }
        if (session2==null){
            //玩家1已经下线了，直接认为玩家2获胜
            response.setWinner(user1.getUserId());
            System.out.println("玩家2 掉线！");
        }
        //把响应构造成JSON字符串，通过session进行传输
        String respJson=objectMapper.writeValueAsString(response);
        if (session1!=null){
            session1.sendMessage(new TextMessage(respJson));
        }
        if (session2!=null){
            session2.sendMessage(new TextMessage(respJson));
        }
        //5、如果当前胜负已分，可以直接销毁房间
        if (response.getWinner()!=0){
            System.out.println("游戏结束！房间即将销毁！roomId="+roomId+"获胜方为"+response.getWinner());
            //更新获胜方和失败方的信息
            int winUserId= response.getWinner();
            int loseUserId= response.getWinner()==user1.getUserId()?user2.getUserId():user1.getUserId();
            userMapper.userWin(winUserId);
            userMapper.userLose(loseUserId);
            //销毁房间
            roomManager.remove(roomId,user1.getUserId(),user2.getUserId());
        }
    }

    private void printBoard() {
        //打印出棋盘
        System.out.println("[打印棋盘信息]"+roomId);
        System.out.println("===================================");
        for (int r = 0; r < MAX_ROW; r++) {
            for (int c = 0; c < MAX_COL; c++) {
                //针对一行之内的若干列，不要打印换行
                System.out.print(board[r][c]);
            }
            //每次遍历完一行之后，在打印换行
            System.out.println();
        }
        System.out.println("===================================");
    }

    //如果玩家1获胜就返回玩家1的userId
    //胜负未分返回0
    private int checkWinner(int row, int col,int chess) {
        //1、先检查所有的行
        //先遍历这五种情况
        for (int c = col-4; c <= col; c++) {
            //针对其中的一种情况，来判定这五个字是不是在一起~
            //不光是这五个子得连着，而且还得和玩家落的子是一样
            try {
                if (board[row][c]==chess && board[row][c+1]==chess
                        && board[row][c+2]==chess && board[row][c+3]==chess
                        && board[row][c+4]==chess){
                    //构成五子棋连珠！胜负已分！
                    return chess==1?user1.getUserId():user2.getUserId();
                }
            }catch (ArrayIndexOutOfBoundsException e){
                //如果出现数组下标越界的情况，就在这里直接忽略这个异常
                continue;
            }
        }
        //2、检查所有的列
        for (int r = row-4; r <= row; r++) {
            //针对其中的一种情况，来判定这五个字是不是在一起~
            //不光是这五个子得连着，而且还得和玩家落的子是一样
            try {
                if (board[r][col]==chess && board[r+1][col]==chess
                        && board[r+2][col]==chess && board[r+3][col]==chess
                        && board[r+4][col]==chess){
                    //构成五子棋连珠！胜负已分！
                    return chess==1?user1.getUserId():user2.getUserId();
                }
            }catch (ArrayIndexOutOfBoundsException e){
                //如果出现数组下标越界的情况，就在这里直接忽略这个异常
                continue;
            }
        }
        //3、左对角线
        for(int r=row-4,c=col-4;r<=row && c<=col;r++,c++){
            //针对其中的一种情况，来判定这五个字是不是在一起~
            //不光是这五个子得连着，而且还得和玩家落的子是一样
            try {
                if (board[r][c]==chess && board[r+1][c+1]==chess
                        && board[r+2][c+2]==chess && board[r+3][c+3]==chess
                        && board[r+4][c+4]==chess){
                    //构成五子棋连珠！胜负已分！
                    return chess==1?user1.getUserId():user2.getUserId();
                }
            }catch (ArrayIndexOutOfBoundsException e){
                //如果出现数组下标越界的情况，就在这里直接忽略这个异常
                continue;
            }
        }
        //4、右对角线
        for(int r=row-4,c=col+4;r<=row && c<=col;r++,c++){
            //针对其中的一种情况，来判定这五个字是不是在一起~
            //不光是这五个子得连着，而且还得和玩家落的子是一样
            try {
                if (board[r][c]==chess && board[r+1][c-1]==chess
                        && board[r+2][c-2]==chess && board[r+3][c-3]==chess
                        && board[r+4][c-4]==chess){
                    //构成五子棋连珠！胜负已分！
                    return chess==1?user1.getUserId():user2.getUserId();
                }
            }catch (ArrayIndexOutOfBoundsException e){
                //如果出现数组下标越界的情况，就在这里直接忽略这个异常
                continue;
            }
        }
        //胜负未分，就直接返回0
        return 0;
    }

    public String getRoomId() {
        return roomId;
    }

    public void setRoomId(String roomId) {
        this.roomId = roomId;
    }

    public User getUser1() {
        return user1;
    }

    public void setUser1(User user1) {
        this.user1 = user1;
    }

    public User getUser2() {
        return user2;
    }

    public void setUser2(User user2) {
        this.user2 = user2;
    }

    public int getWhiteUser() {
        return whiteUser;
    }

    public void setWhiteUser(int whiteUser) {
        this.whiteUser = whiteUser;
    }

    public Room(){
        //构造room的时候生成唯一的字符串表示房间id
        //使用UUID来作为房间id
        roomId= UUID.randomUUID().toString();
        //通过入口类中记录的context来手动获取到前面的RoomManager和OnlineUserManager
        onlineUserManager= DemoApplication.context.getBean(OnlineUserManager.class);
        roomManager=DemoApplication.context.getBean(RoomManager.class);
        userMapper=DemoApplication.context.getBean(UserMapper.class);
    }
}
